package com.ctrip.ec.dal;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.apache.tomcat.jdbc.pool.PoolProperties;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by jiangzy on 2018/6/5.
 */
public class DataSourceManager {

    private final static ConcurrentHashMap<String, DataSource> dsMap = new ConcurrentHashMap<String, DataSource>();

    //可以支持db，可以注入进来
    private final  static  ThreadLocal<String> currentConfigFileName =  new ThreadLocal<String>();

    private   static  void loadDataSource(String configFileName){
        if(dsMap.contains(configFileName) == false){
            Properties dbconfig = new Properties();
            URL  configFileUrl =  DataSourceManager.class.getClassLoader().getResource("META-INF/dal/" + configFileName + ".properties");
//            if(configFileUrl == null){
//                throw new RuntimeException("META-INF/dal/" + configFileName + ".properties 加载失败");
//            }
            String path = configFileUrl.getPath();

            try {
               // InputStream in = new BufferedInputStream(new FileInputStream(path));

                InputStream is = DataSourceManager.class.getClassLoader().getResourceAsStream("META-INF/dal/" + configFileName + ".properties");

                dbconfig.load(is);
            } catch (Exception ex) {
                throw new RuntimeException(path + "文件不存在或访问出错");
            }


            PoolProperties p = new PoolProperties();

            String url = dbconfig.getProperty("url");
            if (url == null || url.length() == 0) {
                throw new RuntimeException("数据库配置缺少url属性");
            } else {
                p.setUrl(url); //设置url
            }

            String driverClassName = dbconfig.getProperty("driverClassName");
            if (driverClassName == null || driverClassName.length() == 0) {
                throw new RuntimeException("数据库配置缺少driverClassName属性");
            } else {
                p.setDriverClassName(driverClassName);//设置驱动
            }

            String userName = dbconfig.getProperty("userName");
            if (userName == null) {
                userName = dbconfig.getProperty("username");
            }
            if (userName == null || userName.length() == 0) {
                throw new RuntimeException("数据库配置缺少username属性");
            } else {
                p.setUsername(userName);//设置用户名
            }

            String password = dbconfig.getProperty("password");
            if (password != null) {
                p.setPassword(password);//设置密码
            }

            String jmxEnabled = dbconfig.getProperty("jmxEnabled");
            if ("true".equals(jmxEnabled)) {
                p.setJmxEnabled(true);//设置java管理扩展是否可用 是否支持JMX
            } else if ("false".equals(jmxEnabled)) {
                p.setJmxEnabled(false);
            }

            String testWhileIdle = dbconfig.getProperty("testWhileIdle");
            if ("true".equals(testWhileIdle)) {
                p.setTestWhileIdle(true);//设置空闲是否可用  空闲对象回收器开启状态
            } else if ( "false".equals(testWhileIdle)) {
                p.setTestWhileIdle(false);
            }



            String testOnBorrow = dbconfig.getProperty("testOnBorrow");
            if ("true".equals(testOnBorrow)) {
                p.setTestOnBorrow(true);//取回连接对链接有效性进行检查    在borrow一个池实例时，是否提前进行池操作；如果为true，则得到的池实例均是可用的；
            } else if ("false".equals(testOnBorrow)) {
                p.setTestOnBorrow(false);
            }

            //      p.setTestOnBorrow(true);

            String testOnReturn = dbconfig.getProperty("testOnReturn");
            if ("true".equals(testOnReturn)) {
                p.setTestOnReturn(true);//测试连接是否有返回
            } else if ("false".equals(testOnReturn)) {
                p.setTestOnReturn(false);
            }

            String validationQuery = dbconfig.getProperty("validationQuery");
            if (validationQuery != null) {
                p.setValidationQuery(validationQuery);//验证连接有效性的方式，这步不能省 测试连接语句,例：SELECT 1
            }

            String validationInterval = dbconfig.getProperty("validationInterval");
            if (validationInterval != null) {
                p.setValidationInterval(Integer.parseInt(validationInterval));//验证间隔时间
            }
            //timeBetweenEvictionRunsMillis 和 minEvictableIdleTimeMillis，
            //他们两个配合，可以持续更新连接池中的连接对象，
            //当timeBetweenEvictionRunsMillis 大于0时，每过timeBetweenEvictionRunsMillis 时间，
            //就会启动一个线程，校验连接池中闲置时间超过minEvictableIdleTimeMillis的连接对象。

            String timeBetweenEvictionRunsMillis = dbconfig.getProperty("timeBetweenEvictionRunsMillis");
            if (timeBetweenEvictionRunsMillis != null) {
                p.setTimeBetweenEvictionRunsMillis(Integer.parseInt(timeBetweenEvictionRunsMillis));
            }

            String minEvictableIdleTimeMillis = dbconfig.getProperty("minEvictableIdleTimeMillis");
            if (minEvictableIdleTimeMillis != null) {
                p.setMinEvictableIdleTimeMillis(Integer.parseInt(minEvictableIdleTimeMillis));
            }

            String maxActive = dbconfig.getProperty("maxActive");
            if (maxActive != null) {
                p.setMaxActive(Integer.parseInt(maxActive));//连接池最大并发容量
            }

            String initialSize = dbconfig.getProperty("initialSize");
            if (initialSize != null) {
                p.setInitialSize(Integer.parseInt(initialSize));//初始化连接池时,创建连接个数
            }

            String maxWait = dbconfig.getProperty("maxWait");
            if (maxWait != null) {
                p.setMaxWait(Integer.parseInt(maxWait));//超时等待时间以毫秒为单位
            }

            String removeAbandonedTimeout = dbconfig.getProperty("removeAbandonedTimeout");
            if (removeAbandonedTimeout != null) {
                p.setRemoveAbandonedTimeout(Integer.parseInt(removeAbandonedTimeout));//超时时间(以秒数为单位)
            }

            String maxIdle = dbconfig.getProperty("maxIdle");
            if (maxIdle != null) {
                p.setMaxIdle(Integer.parseInt(maxIdle));// 最大空闲连接数
            }

            String minIdle = dbconfig.getProperty("minIdle");
            if (minIdle != null) {
                p.setMinIdle(Integer.parseInt(minIdle));//最小空闲连接数
            }

            String logAbandoned = dbconfig.getProperty("logAbandoned");
            if ("true".equals(logAbandoned)) {
                p.setLogAbandoned(true); //是否在自动回收超时连接的时候打印连接的超时错误
            } else if ("false".equals(logAbandoned)) {
                p.setLogAbandoned(false);
            }

            String removeAbandoned = dbconfig.getProperty("removeAbandoned");
            if ("true".equals(removeAbandoned)) {
                p.setRemoveAbandoned(true);//是否自动回收超时连接
            } else if ("false".equals(removeAbandoned)) {
                p.setRemoveAbandoned(false);
            }

            DataSource ds = new DataSource(p);
            dsMap.put(configFileName, ds);
        }
    }

    public  static  void injectDataSource(String configFileName){
        currentConfigFileName.set(configFileName);
        loadDataSource(configFileName);
    }


    private  String  configFileName;//外面传进来的，优先级最高

    public  DataSourceManager(String configFileName){
        this.configFileName = configFileName;
        loadDataSource(configFileName);
    }

     private static final String defaultConfigFileName  = "default";//默认连接串，优先级最低

    public  DataSourceManager(){
        loadDataSource(defaultConfigFileName);
    }

    public  DataSource getDataSource(){
        if(configFileName != null && configFileName.length()>0)
        {
            return dsMap.get(configFileName);
        }
        else if(currentConfigFileName.get() != null && currentConfigFileName.get().length() > 0){
            return dsMap.get(currentConfigFileName.get());
        }
        else{
            return dsMap.get(defaultConfigFileName);
        }
    }
}
